package org.csu.softwaremetrics_demo.metric.lk;

import org.csu.softwaremetrics_demo.entity.common.LKMetricSingleClass;
import org.csu.softwaremetrics_demo.entity.result.Result;
import org.csu.softwaremetrics_demo.metric.Metric;
import org.eclipse.jdt.core.dom.*;

/**
 * @Description:
 * @Author: Jukomu
 * @Package: org.csu.softwaremetrics_demo.metric.lk
 * @Project: SoftwareMetrics_demo
 * @name: NOA
 * @Date: 2025/4/6-19:54
 * @Filename: NOA
 */
public class NOA extends ASTVisitor implements Metric<LKMetricSingleClass> {
    /**
     * 存储方法计数的字段
     */
    private int method_add;

    /**
     * 执行方法，接受一个CompilationUnit对象，一个LKMetricSingleClass对象和一个Result对象
     * @param cu CompilationUnit对象
     * @param singleMetric LKMetricSingleClass对象
     * @param result Result对象
     */
    @Override
    public void execute(CompilationUnit cu, LKMetricSingleClass singleMetric, Result result) {
        cu.accept(this);
    }

    /**
     * 访问TypeDeclaration节点
     * @param node TypeDeclaration节点
     * @return 如果节点是接口，返回false；否则返回false
     */
    @Override
    public boolean visit(TypeDeclaration node) {
        // 遇到接口直接返回
        if (node.isInterface()) {
            return false;
        }

        // 获取类型绑定 null -> 无法获取有效的类型 -> 存在错误拼写或动态类型
        ITypeBinding binding = node.resolveBinding();
        if (binding != null) {
        // 获取类中的所有方法
            MethodDeclaration[] methods = node.getMethods();

        // 遍历所有方法
            for (MethodDeclaration method : methods) {
            // 获取方法绑定
                IMethodBinding methodBinding = method.resolveBinding();
            // 如果方法绑定不为空且该方法没有被重写
                if (methodBinding != null && !isOverriddenMethod(methodBinding)) {
                // 计数器增加
                    method_add++;
                }
            }
        }
    // 返回false，表示不继续访问子节点
        return false;
    }

    /**
     * 设置单个指标的值
     * @param singleMetric LKMetricSingleClass对象
     */
    @Override
    public void setSingleMetric(LKMetricSingleClass singleMetric) {
        singleMetric.setNoa(method_add);
    }

    /**
     * 判断方法是否被重写
     * @param method IMethodBinding对象
     * @return 如果方法被重写，返回true；否则返回false
     */
    private boolean isOverriddenMethod(IMethodBinding method) {
        ITypeBinding declaringClass = method.getDeclaringClass();
        ITypeBinding superclass = declaringClass.getSuperclass();

        while (superclass != null) {
            for (IMethodBinding superMethod : superclass.getDeclaredMethods()) {
                if (method.overrides(superMethod)) {
                    return true;
                }
            }
            superclass = superclass.getSuperclass();
        }
        return false;
    }
}
